<!doctype html><html class="use-motion" lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1"><meta http-equiv="Cache-Control" content="no-transform"><meta http-equiv="Cache-Control" content="no-siteapp"><meta name="google-site-verification" content="0axhmy0-lA3xPbR8wPgyWlMZjwWSCfagKukdyeCQ7LU"><link href="/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css"><link href="/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css"><link href="/css/main.css?v=5.1.0" rel="stylesheet" type="text/css"><meta name="keywords" content="neutron,openstack"><link rel="alternate" href="/atom.xml" title="赵占旭的博客" type="application/atom+xml"><link rel="shortcut icon" type="image/x-icon" href="/favicon.ico?v=5.1.0"><meta name="description" content="我们将从源码的角度查看Neutron Server，使用的版本是Neutron-10.0.0。因为python代码不熟，所以参照了这篇文章。"><meta name="keywords" content="neutron,openstack"><meta property="og:type" content="article"><meta property="og:title" content="Neutron Server 源码分析"><meta property="og:url" content="http://zhaozhanxu.com/2017/06/11/OPENSTACK/2017-06-11-neutron2/index.html"><meta property="og:site_name" content="赵占旭的博客"><meta property="og:description" content="我们将从源码的角度查看Neutron Server，使用的版本是Neutron-10.0.0。因为python代码不熟，所以参照了这篇文章。"><meta property="og:locale" content="en"><meta property="og:updated_time" content="2017-12-11T14:31:18.941Z"><meta name="twitter:card" content="summary"><meta name="twitter:title" content="Neutron Server 源码分析"><meta name="twitter:description" content="我们将从源码的角度查看Neutron Server，使用的版本是Neutron-10.0.0。因为python代码不熟，所以参照了这篇文章。"><script type="text/javascript" id="hexo.configurations">var NexT=window.NexT||{},CONFIG={root:"/",sidebar:{position:"left",display:"post",offset:342,offset_float:0},fancybox:!0,motion:!0}</script><link rel="canonical" href="http://zhaozhanxu.com/2017/06/11/OPENSTACK/2017-06-11-neutron2/"><title> Neutron Server 源码分析 | 赵占旭的博客</title></head><body itemscope itemtype="http://schema.org/WebPage" lang="en"><script>!function(e,a,t,c,n,g,o){e.GoogleAnalyticsObject="ga",e.ga=e.ga||function(){(e.ga.q=e.ga.q||[]).push(arguments)},e.ga.l=1*new Date,g=a.createElement("script"),o=a.getElementsByTagName("script")[0],g.async=1,g.src="//www.google-analytics.com/analytics.js",o.parentNode.insertBefore(g,o)}(window,document),ga("create","3a235f2280210fdd34cebc8c3647e5b8","auto"),ga("send","pageview")</script><script type="text/javascript">var _hmt=_hmt||[];!function(){var e=document.createElement("script");e.src="//hm.baidu.com/hm.js?UA-90327054-1";var t=document.getElementsByTagName("script")[0];t.parentNode.insertBefore(e,t)}()</script><script type="text/javascript">!function(){var e=document.createElement("script");e.src="//tajs.qq.com/stats?sId=60806179";var t=document.getElementsByTagName("script")[0];t.parentNode.insertBefore(e,t)}()</script><div class="container one-collumn sidebar-position-left page-post-detail"><div class="headband"></div><header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader" style="background-image:url(/images/public/home_bg.jpg)"><div class="header-cover"><div class="header-inner"><a class="site-home" href="/">赵占旭的博客</a><div class="site-meta"><div class="custom-logo-site-title"><div href="/" class="brand"><span class="logo-line-before"><i></i></span> <span class="site-title">赵占旭的博客</span><span class="logo-line-after"><i></i></span></div></div><h1 class="site-subtitle" itemprop="description">一花一世界 一叶一菩提</h1></div><div class="site-nav-toggle"> <button><span class="btn-bar"></span><span class="btn-bar"></span><span class="btn-bar"></span></button></div><nav class="site-nav"><ul id="menu" class="menu"><li class="menu-item menu-item-categories"><a href="/categories" rel="section"><i class="menu-item-icon fa fa-fw fa-th"></i><br> Categories</a></li><li class="menu-item menu-item-tags"><a href="/tags" rel="section"><i class="menu-item-icon fa fa-fw fa-tags"></i><br> Tags</a></li><li class="menu-item menu-item-archives"><a href="/archives" rel="section"><i class="menu-item-icon fa fa-fw fa-archive"></i><br> Archives</a></li><li class="menu-item menu-item-about"><a href="/about" rel="section"><i class="menu-item-icon fa fa-fw fa-user"></i><br> About</a></li><li class="menu-item menu-item-search"><a href="javascript:" ; class="popup-trigger"><i class="menu-item-icon fa fa-search fa-fw"></i><br> Search</a></li></ul><div class="site-search"><div class="popup local-search-popup"><div class="local-search-header clearfix"><span class="search-icon"><i class="fa fa-search"></i></span><span class="popup-btn-close"><i class="fa fa-times-circle"></i></span><div class="local-search-input-wrapper"> <input autocapitalize="off" autocomplete="off" autocorrect="off" placeholder="search.placeholder" spellcheck="false" type="text" id="local-search-input"></div></div><div id="local-search-result"></div></div></div></nav></div><div class="header-post"><div class="post-header"><div class="tags"> <a href="/tags/openstack/" rel="tag" title="openstack">openstack</a> <a href="/tags/SDN/" rel="tag" title="SDN">SDN</a> <a href="/tags/neutron/" rel="tag" title="neutron">neutron</a></div><h1>Neutron Server 源码分析</h1><h2 class="subtitle">How old are you</h2><div class="post-time"> <span class="post-meta-item-text">Posted on</span> <time itemprop="dateCreated" datetime="2017-06-11T00:00:00+08:00" content="2017-06-11" title="2017-06-11 00:00:00">2017-06-11</time></div></div></div></div></header><main id="main" class="main"><div class="main-inner"><div class="content-wrap"><div id="content" class="content"><div id="posts" class="posts-expand"><article class="post post-type-normal" itemscope itemtype="http://schema.org/Article"><link itemprop="mainEntityOfPage" href="http://zhaozhanxu.com/2017/06/11/OPENSTACK/2017-06-11-neutron2/"><span style="display:none" itemprop="author" itemscope itemtype="http://schema.org/Person"><meta itemprop="name" content="赵占旭"><meta itemprop="description" content=""><meta itemprop="image" content="/images/public/me.jpg"></span><span style="display:none" itemprop="publisher" itemscope itemtype="http://schema.org/Organization"><meta itemprop="name" content="赵占旭的博客"> <span style="display:none" itemprop="logo" itemscope itemtype="http://schema.org/ImageObject"><img style="display:none" itemprop="url image" alt="赵占旭的博客" src=""></span></span><div class="post-inner"><header class="post-header"><h2 class="post-title" itemprop="name headline"> Neutron Server 源码分析</h2><div class="post-meta"><span class="post-time"><span class="post-meta-item-icon"><i class="fa fa-calendar-o"></i></span> <span class="post-meta-item-text">Posted on</span> <time title="Post created" itemprop="dateCreated datePublished" datetime="2017-06-11T00:00:00+08:00">2017-06-11</time></span></div></header><div class="post-info"><div class="post-categories"> <a class="color" href="/categories/openstack/" rel="tag">openstack</a></div><div class="post-tags"> <a class="color" href="/tags/openstack/" rel="tag">openstack</a> <a class="color" href="/tags/SDN/" rel="tag">SDN</a> <a class="color" href="/tags/neutron/" rel="tag">neutron</a></div><div class="clearfix"></div></div><div class="post-body" itemprop="articleBody"><p>我们将从源码的角度查看Neutron Server，使用的版本是Neutron-10.0.0。因为python代码不熟，所以参照了<a href="http://blog.csdn.net/happyanger6/article/details/54586463" target="_blank" rel="noopener">这篇文章</a>。</p><a id="more"></a><h1 id="Neutron-Server-能力"><a href="#Neutron-Server-能力" class="headerlink" title="Neutron Server 能力"></a>Neutron Server 能力</h1><hr><p>由上一篇得知，Neutron Server向上提供了API，向下调用Plugin，我们就依次查看一下</p><ul><li>入口函数，主要是Neutron Server从哪里调入的。</li><li>Core API，对外提供管理Network，Subnet和Port的RESTful的API。</li><li>Extension API，对外提供管理Router, Load Balance, Firewall等资源的RESTful API。</li><li>Common Service，认证和校验API的请求，这块我们先不关注</li><li>Neutron Core，Neutron Server的核心处理程序，通过调用相应的Plugin处理请求。这里因为和其他部分结合比较紧密，就不单独拿出来看了。</li><li>Core Plugin API，定义了Core Plgin的抽象功能集合，Neutron Core通过该API调用相应的Core Plugin。</li><li>Extension Plugin API， 定义了Service Plugin的抽象功能集合，Neutron Core通过该API调用相应的Service Plugin。</li><li>Core Plugin，实现了Core Plugin API，在数据库中维护network, Subnet和Port的状态，并负责调用相应的Agent在Network Provider上执行相关操作，比如创建Network。这块我们单独后续单独看。</li><li>Service Plugin，实现了Extension Plugin API，在数据库中维护Router, Load Balance, Security Group等资源的状态，并负责调用相应的Agent在Network Provider上执行相关操作，比如创建Router。这块我们后续也单独看。</li></ul><h1 id="入口函数"><a href="#入口函数" class="headerlink" title="入口函数"></a>入口函数</h1><hr><p>从setup.cfg看到入口函数位于<code>neutron.cmd.eventlet.server:main</code>，位于<code>neutron/cmd/server/__init__.py</code>。</p><p><code>main--&gt;server.boot_server--&gt;_main_neutron_server--&gt;wsgi_eventlet.eventlet_wsgi_server</code></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># neutron/server/wsgi_eventlet.py</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">eventlet_wsgi_server</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="comment"># 注册neutron-api，并且启动相应的进程，并且进行监听</span></span><br><span class="line">    neutron_api = service.serve_wsgi(service.NeutronApiService)</span><br><span class="line">    <span class="comment"># 利用eventlet线程池启动Plugin和RPC</span></span><br><span class="line">    start_api_and_rpc_workers(neutron_api)</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># neutron/service.py</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">serve_wsgi</span><span class="params">(cls)</span>:</span></span><br><span class="line">    <span class="comment"># 创建一个class NeutronApiService实例</span></span><br><span class="line">    <span class="comment"># app_name = 'neutron'</span></span><br><span class="line">    service = cls.create()</span><br><span class="line">    <span class="comment"># 启动API Server</span></span><br><span class="line">    <span class="comment"># 此处继承了class NeutronApiService的父类class WsgiService</span></span><br><span class="line">    service.start()</span><br><span class="line">    registry.notify(resources.PROCESS, events.BEFORE_SPAWN, service)</span><br><span class="line">    <span class="keyword">return</span> service</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">WsgiService</span><span class="params">(object)</span>:</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">start</span><span class="params">(self)</span>:</span></span><br><span class="line">        <span class="comment"># 调用_run_wsgi加载</span></span><br><span class="line">        self.wsgi_app = _run_wsgi(self.app_name)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">_run_wsgi</span><span class="params">(app_name)</span>:</span></span><br><span class="line">    <span class="comment"># 先从配置文件api-paste.ini读取出要加载的app</span></span><br><span class="line">    <span class="comment"># 默认配置的app如下，下面会稍微介绍一下为何</span></span><br><span class="line">    <span class="comment"># paste.app_factory =  neutron.api.v2.router:APIRouter.factory</span></span><br><span class="line">    <span class="comment"># 所以这一步实际调用的是 neutron.api.v2.router ApiRouter实例</span></span><br><span class="line">    <span class="comment"># 的factory生成一个router实例</span></span><br><span class="line">    <span class="comment"># 最终创建一些controller的URL</span></span><br><span class="line">    app = config.load_paste_app(app_name)</span><br><span class="line">    <span class="comment"># 创建neutron的协程</span></span><br><span class="line">    <span class="comment"># 监听host的9696端口</span></span><br><span class="line">    <span class="comment"># 创建n个api进程，取决于配置文件api_workers</span></span><br><span class="line">    <span class="keyword">return</span> run_wsgi_app(app)</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># neutron/server/wsgi_eventlet.py</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">start_api_and_rpc_workers</span><span class="params">(neutron_api)</span>:</span></span><br><span class="line">    <span class="comment"># 可能是为plugin和RPC创建进程</span></span><br><span class="line">    <span class="comment"># plugin的worker数量取决于配置文件的service_plugins</span></span><br><span class="line">    <span class="comment"># RPC的数量取决于配置文件的rpc_workers</span></span><br><span class="line">    worker_launcher = service.start_all_workers()</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 创建协程坐等两个服务结束</span></span><br><span class="line">    pool = eventlet.GreenPool()</span><br><span class="line">    api_thread = pool.spawn(neutron_api.wait)</span><br><span class="line">    plugin_workers_thread = pool.spawn(worker_launcher.wait)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 确保其中一个服务挂掉后，结束另外一个</span></span><br><span class="line">    api_thread.link(<span class="keyword">lambda</span> gt: plugin_workers_thread.kill())</span><br><span class="line">    plugin_workers_thread.link(<span class="keyword">lambda</span> gt: api_thread.kill())</span><br><span class="line"></span><br><span class="line">    pool.waitall()</span><br></pre></td></tr></table></figure><h1 id="Core-API-amp-Extension-API"><a href="#Core-API-amp-Extension-API" class="headerlink" title="Core API &amp; Extension API"></a>Core API &amp; Extension API</h1><hr><p>Core API主要对外提供管理Network, Subnet和Port等的RESTful API。<br>Extension API对外提供管理Router, Load Balance, Firewall等资源的RESTful API。<br>我们可以通过命令行查看API。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br></pre></td><td class="code"><pre><span class="line">curl http://localhost:9696/v2.0/</span><br><span class="line"></span><br><span class="line">&#123;<span class="string">"resources"</span>: [</span><br><span class="line">   &#123;<span class="string">"links"</span>: [&#123;<span class="string">"href"</span>: <span class="string">"http://localhost:9696/v2.0/subnets"</span>, <span class="string">"rel"</span>: <span class="string">"self"</span>&#125;],</span><br><span class="line">       <span class="string">"name"</span>: <span class="string">"subnet"</span>, <span class="string">"collection"</span>: <span class="string">"subnets"</span>&#125;,</span><br><span class="line">   &#123;<span class="string">"links"</span>: [&#123;<span class="string">"href"</span>: <span class="string">"http://localhost:9696/v2.0/subnetpools"</span>, <span class="string">"rel"</span>: <span class="string">"self"</span>&#125;],</span><br><span class="line">       <span class="string">"name"</span>: <span class="string">"subnetpool"</span>, <span class="string">"collection"</span>: <span class="string">"subnetpools"</span>&#125;,</span><br><span class="line">   &#123;<span class="string">"links"</span>: [&#123;<span class="string">"href"</span>: <span class="string">"http://localhost:9696/v2.0/networks"</span>, <span class="string">"rel"</span>: <span class="string">"self"</span>&#125;],</span><br><span class="line">       <span class="string">"name"</span>: <span class="string">"network"</span>, <span class="string">"collection"</span>: <span class="string">"networks"</span>&#125;,</span><br><span class="line">   &#123;<span class="string">"links"</span>: [&#123;<span class="string">"href"</span>: <span class="string">"http://localhost:9696/v2.0/ports"</span>, <span class="string">"rel"</span>: <span class="string">"self"</span>&#125;],</span><br><span class="line">       <span class="string">"name"</span>: <span class="string">"port"</span>, <span class="string">"collection"</span>: <span class="string">"ports"</span>&#125;]&#125;</span><br><span class="line"></span><br><span class="line">curl http://localhost:9696/v2.0/extensions</span><br><span class="line"></span><br><span class="line">&#123;<span class="string">"extensions"</span>: [</span><br><span class="line">    &#123;<span class="string">"alias"</span>: <span class="string">"default-subnetpools"</span>, <span class="string">"updated"</span>: <span class="string">"2016-02-18T18:00:00-00:00"</span>, <span class="string">"name"</span>: <span class="string">"Default Subnetpools"</span>, <span class="string">"links"</span>: [], <span class="string">"description"</span>: <span class="string">"Provides ability to mark and use a subnetpool as the default"</span>&#125;,</span><br><span class="line">    &#123;<span class="string">"alias"</span>: <span class="string">"network-ip-availability"</span>, <span class="string">"updated"</span>: <span class="string">"2015-09-24T00:00:00-00:00"</span>, <span class="string">"name"</span>: <span class="string">"Network IP Availability"</span>, <span class="string">"links"</span>: [], <span class="string">"description"</span>: <span class="string">"Provides IP availability data for each network and subnet."</span>&#125;,</span><br><span class="line">    &#123;<span class="string">"alias"</span>: <span class="string">"network_availability_zone"</span>, <span class="string">"updated"</span>: <span class="string">"2015-01-01T10:00:00-00:00"</span>, <span class="string">"name"</span>: <span class="string">"Network Availability Zone"</span>, <span class="string">"links"</span>: [], <span class="string">"description"</span>: <span class="string">"Availability zone support for network."</span>&#125;,</span><br><span class="line">    &#123;<span class="string">"alias"</span>: <span class="string">"auto-allocated-topology"</span>, <span class="string">"updated"</span>: <span class="string">"2016-01-01T00:00:00-00:00"</span>, <span class="string">"name"</span>: <span class="string">"Auto Allocated Topology Services"</span>, <span class="string">"links"</span>: [], <span class="string">"description"</span>: <span class="string">"Auto Allocated Topology Services."</span>&#125;,</span><br><span class="line">    &#123;<span class="string">"alias"</span>: <span class="string">"ext-gw-mode"</span>, <span class="string">"updated"</span>: <span class="string">"2013-03-28T10:00:00-00:00"</span>, <span class="string">"name"</span>: <span class="string">"Neutron L3 Configurable external gateway mode"</span>, <span class="string">"links"</span>: [], <span class="string">"description"</span>: <span class="string">"Extension of the router abstraction for specifying whether SNAT should occur on the external gateway"</span>&#125;,</span><br><span class="line">    &#123;<span class="string">"alias"</span>: <span class="string">"binding"</span>, <span class="string">"updated"</span>: <span class="string">"2014-02-03T10:00:00-00:00"</span>, <span class="string">"name"</span>: <span class="string">"Port Binding"</span>, <span class="string">"links"</span>: [], <span class="string">"description"</span>: <span class="string">"Expose port bindings of a virtual port to external application"</span>&#125;,</span><br><span class="line">    &#123;<span class="string">"alias"</span>: <span class="string">"metering"</span>, <span class="string">"updated"</span>: <span class="string">"2013-06-12T10:00:00-00:00"</span>, <span class="string">"name"</span>: <span class="string">"Neutron Metering"</span>, <span class="string">"links"</span>: [], <span class="string">"description"</span>: <span class="string">"Neutron Metering extension."</span>&#125;,</span><br><span class="line">    &#123;<span class="string">"alias"</span>: <span class="string">"agent"</span>, <span class="string">"updated"</span>: <span class="string">"2013-02-03T10:00:00-00:00"</span>, <span class="string">"name"</span>: <span class="string">"agent"</span>, <span class="string">"links"</span>: [], <span class="string">"description"</span>: <span class="string">"The agent management extension."</span>&#125;,</span><br><span class="line">    &#123;<span class="string">"alias"</span>: <span class="string">"subnet_allocation"</span>, <span class="string">"updated"</span>: <span class="string">"2015-03-30T10:00:00-00:00"</span>, <span class="string">"name"</span>: <span class="string">"Subnet Allocation"</span>, <span class="string">"links"</span>: [], <span class="string">"description"</span>: <span class="string">"Enables allocation of subnets from a subnet pool"</span>&#125;,</span><br><span class="line">    &#123;<span class="string">"alias"</span>: <span class="string">"l3_agent_scheduler"</span>, <span class="string">"updated"</span>: <span class="string">"2013-02-07T10:00:00-00:00"</span>, <span class="string">"name"</span>: <span class="string">"L3 Agent Scheduler"</span>, <span class="string">"links"</span>: [], <span class="string">"description"</span>: <span class="string">"Schedule routers among l3 agents"</span>&#125;,</span><br><span class="line">    &#123;<span class="string">"alias"</span>: <span class="string">"tag"</span>, <span class="string">"updated"</span>: <span class="string">"2016-01-01T00:00:00-00:00"</span>, <span class="string">"name"</span>: <span class="string">"Tag support"</span>, <span class="string">"links"</span>: [], <span class="string">"description"</span>: <span class="string">"Enables to set tag on resources."</span>&#125;,</span><br><span class="line">    &#123;<span class="string">"alias"</span>: <span class="string">"external-net"</span>, <span class="string">"updated"</span>: <span class="string">"2013-01-14T10:00:00-00:00"</span>, <span class="string">"name"</span>: <span class="string">"Neutron external network"</span>, <span class="string">"links"</span>: [], <span class="string">"description"</span>: <span class="string">"Adds external network attribute to network resource."</span>&#125;,</span><br><span class="line">    &#123;<span class="string">"alias"</span>: <span class="string">"flavors"</span>, <span class="string">"updated"</span>: <span class="string">"2015-09-17T10:00:00-00:00"</span>, <span class="string">"name"</span>: <span class="string">"Neutron Service Flavors"</span>, <span class="string">"links"</span>: [], <span class="string">"description"</span>: <span class="string">"Flavor specification for Neutron advanced services"</span>&#125;,</span><br><span class="line">    &#123;<span class="string">"alias"</span>: <span class="string">"net-mtu"</span>, <span class="string">"updated"</span>: <span class="string">"2015-03-25T10:00:00-00:00"</span>, <span class="string">"name"</span>: <span class="string">"Network MTU"</span>, <span class="string">"links"</span>: [], <span class="string">"description"</span>: <span class="string">"Provides MTU attribute for a network resource."</span>&#125;,</span><br><span class="line">    &#123;<span class="string">"alias"</span>: <span class="string">"availability_zone"</span>, <span class="string">"updated"</span>: <span class="string">"2015-01-01T10:00:00-00:00"</span>, <span class="string">"name"</span>: <span class="string">"Availability Zone"</span>, <span class="string">"links"</span>: [], <span class="string">"description"</span>: <span class="string">"The availability zone extension."</span>&#125;,</span><br><span class="line">    &#123;<span class="string">"alias"</span>: <span class="string">"quotas"</span>, <span class="string">"updated"</span>: <span class="string">"2012-07-29T10:00:00-00:00"</span>, <span class="string">"name"</span>: <span class="string">"Quota management support"</span>, <span class="string">"links"</span>: [], <span class="string">"description"</span>: <span class="string">"Expose functions for quotas management per tenant"</span>&#125;,</span><br><span class="line">    &#123;<span class="string">"alias"</span>: <span class="string">"l3-ha"</span>, <span class="string">"updated"</span>: <span class="string">"2014-04-26T00:00:00-00:00"</span>, <span class="string">"name"</span>: <span class="string">"HA Router extension"</span>, <span class="string">"links"</span>: [], <span class="string">"description"</span>: <span class="string">"Add HA capability to routers."</span>&#125;,</span><br><span class="line">    &#123;<span class="string">"alias"</span>: <span class="string">"provider"</span>, <span class="string">"updated"</span>: <span class="string">"2012-09-07T10:00:00-00:00"</span>, <span class="string">"name"</span>: <span class="string">"Provider Network"</span>, <span class="string">"links"</span>: [], <span class="string">"description"</span>: <span class="string">"Expose mapping of virtual networks to physical networks"</span>&#125;,</span><br><span class="line">    &#123;<span class="string">"alias"</span>: <span class="string">"multi-provider"</span>, <span class="string">"updated"</span>: <span class="string">"2013-06-27T10:00:00-00:00"</span>, <span class="string">"name"</span>: <span class="string">"Multi Provider Network"</span>, <span class="string">"links"</span>: [], <span class="string">"description"</span>: <span class="string">"Expose mapping of virtual networks to multiple physical networks"</span>&#125;,</span><br><span class="line">    &#123;<span class="string">"alias"</span>: <span class="string">"address-scope"</span>, <span class="string">"updated"</span>: <span class="string">"2015-07-26T10:00:00-00:00"</span>, <span class="string">"name"</span>: <span class="string">"Address scope"</span>, <span class="string">"links"</span>: [], <span class="string">"description"</span>: <span class="string">"Address scopes extension."</span>&#125;,</span><br><span class="line">    &#123;<span class="string">"alias"</span>: <span class="string">"extraroute"</span>, <span class="string">"updated"</span>: <span class="string">"2013-02-01T10:00:00-00:00"</span>, <span class="string">"name"</span>: <span class="string">"Neutron Extra Route"</span>, <span class="string">"links"</span>: [], <span class="string">"description"</span>: <span class="string">"Extra routes configuration for L3 router"</span>&#125;,</span><br><span class="line">    &#123;<span class="string">"alias"</span>: <span class="string">"subnet-service-types"</span>, <span class="string">"updated"</span>: <span class="string">"2016-03-15T18:00:00-00:00"</span>, <span class="string">"name"</span>: <span class="string">"Subnet service types"</span>, <span class="string">"links"</span>: [], <span class="string">"description"</span>: <span class="string">"Provides ability to set the subnet service_types field"</span>&#125;,</span><br><span class="line">    &#123;<span class="string">"alias"</span>: <span class="string">"standard-attr-timestamp"</span>, <span class="string">"updated"</span>: <span class="string">"2016-09-12T10:00:00-00:00"</span>, <span class="string">"name"</span>: <span class="string">"Resource timestamps"</span>, <span class="string">"links"</span>: [], <span class="string">"description"</span>: <span class="string">"Adds created_at and updated_at fields to all Neutron resources that have Neutron standard attributes."</span>&#125;,</span><br><span class="line">    &#123;<span class="string">"alias"</span>: <span class="string">"service-type"</span>, <span class="string">"updated"</span>: <span class="string">"2013-01-20T00:00:00-00:00"</span>, <span class="string">"name"</span>: <span class="string">"Neutron Service Type Management"</span>, <span class="string">"links"</span>: [], <span class="string">"description"</span>: <span class="string">"API for retrieving service providers for Neutron advanced services"</span>&#125;,</span><br><span class="line">    &#123;<span class="string">"alias"</span>: <span class="string">"l3-flavors"</span>, <span class="string">"updated"</span>: <span class="string">"2016-05-17T00:00:00-00:00"</span>, <span class="string">"name"</span>: <span class="string">"Router Flavor Extension"</span>, <span class="string">"links"</span>: [], <span class="string">"description"</span>: <span class="string">"Flavor support for routers."</span>&#125;,</span><br><span class="line">    &#123;<span class="string">"alias"</span>: <span class="string">"port-security"</span>, <span class="string">"updated"</span>: <span class="string">"2012-07-23T10:00:00-00:00"</span>, <span class="string">"name"</span>: <span class="string">"Port Security"</span>, <span class="string">"links"</span>: [], <span class="string">"description"</span>: <span class="string">"Provides port security"</span>&#125;,</span><br><span class="line">    &#123;<span class="string">"alias"</span>: <span class="string">"extra_dhcp_opt"</span>, <span class="string">"updated"</span>: <span class="string">"2013-03-17T12:00:00-00:00"</span>, <span class="string">"name"</span>: <span class="string">"Neutron Extra DHCP opts"</span>, <span class="string">"links"</span>: [], <span class="string">"description"</span>: <span class="string">"Extra options configuration for DHCP. For example PXE boot options to DHCP clients can be specified (e.g. tftp-server, server-ip-address, bootfile-name)"</span>&#125;,</span><br><span class="line">    &#123;<span class="string">"alias"</span>: <span class="string">"standard-attr-revisions"</span>, <span class="string">"updated"</span>: <span class="string">"2016-04-11T10:00:00-00:00"</span>, <span class="string">"name"</span>: <span class="string">"Resource revision numbers"</span>, <span class="string">"links"</span>: [], <span class="string">"description"</span>: <span class="string">"This extension will display the revision number of neutron resources."</span>&#125;,</span><br><span class="line">    &#123;<span class="string">"alias"</span>: <span class="string">"pagination"</span>, <span class="string">"updated"</span>: <span class="string">"2016-06-12T00:00:00-00:00"</span>, <span class="string">"name"</span>: <span class="string">"Pagination support"</span>, <span class="string">"links"</span>: [], <span class="string">"description"</span>: <span class="string">"Extension that indicates that pagination is enabled."</span>&#125;,</span><br><span class="line">    &#123;<span class="string">"alias"</span>: <span class="string">"sorting"</span>, <span class="string">"updated"</span>: <span class="string">"2016-06-12T00:00:00-00:00"</span>, <span class="string">"name"</span>: <span class="string">"Sorting support"</span>, <span class="string">"links"</span>: [], <span class="string">"description"</span>: <span class="string">"Extension that indicates that sorting is enabled."</span>&#125;,</span><br><span class="line">    &#123;<span class="string">"alias"</span>: <span class="string">"security-group"</span>, <span class="string">"updated"</span>: <span class="string">"2012-10-05T10:00:00-00:00"</span>, <span class="string">"name"</span>: <span class="string">"security-group"</span>, <span class="string">"links"</span>: [], <span class="string">"description"</span>: <span class="string">"The security groups extension."</span>&#125;,</span><br><span class="line">    &#123;<span class="string">"alias"</span>: <span class="string">"dhcp_agent_scheduler"</span>, <span class="string">"updated"</span>: <span class="string">"2013-02-07T10:00:00-00:00"</span>, <span class="string">"name"</span>: <span class="string">"DHCP Agent Scheduler"</span>, <span class="string">"links"</span>: [], <span class="string">"description"</span>: <span class="string">"Schedule networks among dhcp agents"</span>&#125;,</span><br><span class="line">    &#123;<span class="string">"alias"</span>: <span class="string">"router_availability_zone"</span>, <span class="string">"updated"</span>: <span class="string">"2015-01-01T10:00:00-00:00"</span>, <span class="string">"name"</span>: <span class="string">"Router Availability Zone"</span>, <span class="string">"links"</span>: [], <span class="string">"description"</span>: <span class="string">"Availability zone support for router."</span>&#125;,</span><br><span class="line">    &#123;<span class="string">"alias"</span>: <span class="string">"rbac-policies"</span>, <span class="string">"updated"</span>: <span class="string">"2015-06-17T12:15:12-00:00"</span>, <span class="string">"name"</span>: <span class="string">"RBAC Policies"</span>, <span class="string">"links"</span>: [], <span class="string">"description"</span>: <span class="string">"Allows creation and modification of policies that control tenant access to resources."</span>&#125;,</span><br><span class="line">    &#123;<span class="string">"alias"</span>: <span class="string">"tag-ext"</span>, <span class="string">"updated"</span>: <span class="string">"2017-01-01T00:00:00-00:00"</span>, <span class="string">"name"</span>: <span class="string">"Tag support for resources: subnet, subnetpool, port, router"</span>, <span class="string">"links"</span>: [], <span class="string">"description"</span>: <span class="string">"Extends tag support to more L2 and L3 resources."</span>&#125;,</span><br><span class="line">    &#123;<span class="string">"alias"</span>: <span class="string">"standard-attr-description"</span>, <span class="string">"updated"</span>: <span class="string">"2016-02-10T10:00:00-00:00"</span>, <span class="string">"name"</span>: <span class="string">"standard-attr-description"</span>, <span class="string">"links"</span>: [], <span class="string">"description"</span>: <span class="string">"Extension to add descriptions to standard attributes"</span>&#125;,</span><br><span class="line">    &#123;<span class="string">"alias"</span>: <span class="string">"router"</span>, <span class="string">"updated"</span>: <span class="string">"2012-07-20T10:00:00-00:00"</span>, <span class="string">"name"</span>: <span class="string">"Neutron L3 Router"</span>, <span class="string">"links"</span>: [], <span class="string">"description"</span>: <span class="string">"Router abstraction for basic L3 forwarding between L2 Neutron networks and access to external networks via a NAT gateway."</span>&#125;,</span><br><span class="line">    &#123;<span class="string">"alias"</span>: <span class="string">"allowed-address-pairs"</span>, <span class="string">"updated"</span>: <span class="string">"2013-07-23T10:00:00-00:00"</span>, <span class="string">"name"</span>: <span class="string">"Allowed Address Pairs"</span>, <span class="string">"links"</span>: [], <span class="string">"description"</span>: <span class="string">"Provides allowed address pairs"</span>&#125;,</span><br><span class="line">    &#123;<span class="string">"alias"</span>: <span class="string">"project-id"</span>, <span class="string">"updated"</span>: <span class="string">"2016-09-09T09:09:09-09:09"</span>, <span class="string">"name"</span>: <span class="string">"project_id field enabled"</span>, <span class="string">"links"</span>: [], <span class="string">"description"</span>: <span class="string">"Extension that indicates that project_id field is enabled."</span>&#125;,</span><br><span class="line">    &#123;<span class="string">"alias"</span>: <span class="string">"dvr"</span>, <span class="string">"updated"</span>: <span class="string">"2014-06-1T10:00:00-00:00"</span>, <span class="string">"name"</span>: <span class="string">"Distributed Virtual Router"</span>, <span class="string">"links"</span>: [], <span class="string">"description"</span>: <span class="string">"Enables configuration of Distributed Virtual Routers."</span>&#125;]&#125;</span><br></pre></td></tr></table></figure><p>接下来我们看一下代码，从上面可以看到<code>_run_wsgi(app_name)</code>主要负责API的服务。<br>我们分别看一下，首先是<code>app = config.load_paste_app(app_name)</code>的操作，主要是根据配置文件<code>api-paste.ini</code>获取需要加载的app，配置文件相关信息如下：</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">[composite:neutron]</span><br><span class="line">use = egg:Paste#urlmap</span><br><span class="line">/: neutronversions_composite</span><br><span class="line">/v2.0: neutronapi_v2_0</span><br><span class="line"></span><br><span class="line"># neutron/api/versions.py中class Versions中是v2.0</span><br><span class="line">[composite:neutronapi_v2_0]</span><br><span class="line">use = call:neutron.auth:pipeline_factory</span><br><span class="line">noauth = cors http_proxy_to_wsgi request_id catch_errors extensions neutronapiapp_v2_0</span><br><span class="line">keystone = cors http_proxy_to_wsgi request_id catch_errors authtoken keystonecontext extensions neutronapiapp_v2_0</span><br><span class="line"></span><br><span class="line">[app:neutronapiapp_v2_0]</span><br><span class="line">paste.app_factory = neutron.api.v2.router:APIRouter.factory</span><br></pre></td></tr></table></figure><p>从配置文件知道我们需要加载的app是v2版本的API创建，我们从下面的代码可以得知，我们这个应用是来创建API的，只不过这里只是生成了API的URL和路由，创建的信息如上面查看的API所示，但是并没有进行正常的监听。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># neutron/api/v2/router.py</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">APIRouter</span><span class="params">(base_wsgi.Router)</span>:</span></span><br><span class="line">    <span class="comment"># 方法构造了一个APIRouter对象作为app返回</span></span><br><span class="line">    <span class="comment"># 所以我们需要分析一下构造函数__init__</span></span><br><span class="line"><span class="meta">    @classmethod</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">factory</span><span class="params">(cls, global_config, **local_config)</span>:</span></span><br><span class="line">        <span class="keyword">return</span> cls(**local_config)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># Core API的构造，下面详细分析</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self, **local_config)</span>:</span></span><br><span class="line">        <span class="comment"># 创建一个router，构造URL和controller的映射</span></span><br><span class="line">        mapper = routes_mapper.Mapper()</span><br><span class="line">        <span class="comment"># class NeutronManager会创建一个core plugin</span></span><br><span class="line">        <span class="comment"># 我们的配置core_plugin = ml2</span></span><br><span class="line">        <span class="comment"># 并且加载service_plugins = router,metering,qos</span></span><br><span class="line">        <span class="comment"># service_plugins还要加上默认的plugins</span></span><br><span class="line">        <span class="comment"># 默认的在neutron/plugins/common/constants.py的</span></span><br><span class="line">        <span class="comment"># DEFAULT_SERVICE_PLUGINS</span></span><br><span class="line">        manager.init()</span><br><span class="line">        <span class="comment"># 所以这里获取的plugin是ml2的plugin</span></span><br><span class="line">        plugin = directory.get_plugin()</span><br><span class="line">        <span class="comment"># 从neutron/extensions目录下加载所有上面提到的service_plugins</span></span><br><span class="line">        ext_mgr = extensions.PluginAwareExtensionManager.get_instance()</span><br><span class="line">        <span class="comment"># 扩展资源neutron/api/v2/attributes.py中的RESOURCE_ATTRIBUTE_MAP</span></span><br><span class="line">        ext_mgr.extend_resources(<span class="string">"2.0"</span>, attributes.RESOURCE_ATTRIBUTE_MAP)</span><br><span class="line"></span><br><span class="line">        <span class="comment"># COLLECTION_ACTIONS = ['index', 'create']</span></span><br><span class="line">        <span class="comment"># MEMBER_ACTIONS = ['show', 'update', 'delete']</span></span><br><span class="line">        col_kwargs = dict(collection_actions=COLLECTION_ACTIONS,</span><br><span class="line">                          member_actions=MEMBER_ACTIONS)</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">def</span> <span class="title">_map_resource</span><span class="params">(collection, resource, params, parent=None)</span>:</span></span><br><span class="line">            allow_bulk = cfg.CONF.allow_bulk</span><br><span class="line">            controller = base.create_resource(</span><br><span class="line">                collection, resource, plugin, params, allow_bulk=allow_bulk,</span><br><span class="line">                parent=parent, allow_pagination=<span class="keyword">True</span>,</span><br><span class="line">                allow_sorting=<span class="keyword">True</span>)</span><br><span class="line">            path_prefix = <span class="keyword">None</span></span><br><span class="line">            <span class="keyword">if</span> parent:</span><br><span class="line">                path_prefix = <span class="string">"/%s/&#123;%s_id&#125;/%s"</span> % (parent[<span class="string">'collection_name'</span>],</span><br><span class="line">                                                  parent[<span class="string">'member_name'</span>],</span><br><span class="line">                                                  collection)</span><br><span class="line">            mapper_kwargs = dict(controller=controller,</span><br><span class="line">                                 requirements=REQUIREMENTS,</span><br><span class="line">                                 path_prefix=path_prefix,</span><br><span class="line">                                 **col_kwargs)</span><br><span class="line">            <span class="keyword">return</span> mapper.collection(collection, resource,</span><br><span class="line">                                     **mapper_kwargs)</span><br><span class="line"></span><br><span class="line">        <span class="comment"># 构造根URL对应的信息</span></span><br><span class="line">        <span class="comment"># RESOURCES = &#123;'network': 'networks', 'subnet': 'subnets',</span></span><br><span class="line">        <span class="comment">#              'subnetpool': 'subnetpools', 'port': 'ports'&#125;</span></span><br><span class="line">        mapper.connect(<span class="string">'index'</span>, <span class="string">'/'</span>, controller=Index(RESOURCES))</span><br><span class="line">        <span class="keyword">for</span> resource <span class="keyword">in</span> RESOURCES:</span><br><span class="line">            <span class="comment"># 分别构造上面的几个URL，信息来自于上面的RESOURCE_ATTRIBUTE_MAP信息</span></span><br><span class="line">            <span class="comment"># 其中一个查看 curl http://localhost:9696/v2.0/subnets</span></span><br><span class="line">            <span class="comment"># &#123;"subnets": []&#125;</span></span><br><span class="line">            _map_resource(RESOURCES[resource], resource,</span><br><span class="line">                          attributes.RESOURCE_ATTRIBUTE_MAP.get(</span><br><span class="line">                              RESOURCES[resource], dict()))</span><br><span class="line">            <span class="comment"># 注册事件，监听数据库的变动</span></span><br><span class="line">            resource_registry.register_resource_by_name(resource)</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> resource <span class="keyword">in</span> SUB_RESOURCES:</span><br><span class="line">            _map_resource(SUB_RESOURCES[resource][<span class="string">'collection_name'</span>], resource,</span><br><span class="line">                          attributes.RESOURCE_ATTRIBUTE_MAP.get(</span><br><span class="line">                              SUB_RESOURCES[resource][<span class="string">'collection_name'</span>],</span><br><span class="line">                              dict()),</span><br><span class="line">                          SUB_RESOURCES[resource][<span class="string">'parent'</span>])</span><br><span class="line"></span><br><span class="line">        policy.reset()</span><br><span class="line">        <span class="comment"># 初始化路由请求</span></span><br><span class="line">        super(APIRouter, self).__init__(mapper)</span><br></pre></td></tr></table></figure><p>接下来我们需要看一下<code>run_wsgi_app(app)</code>的操作，主要是根据配置创建n个API Worker的进程，然后进行监听。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># neutron/service.py</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">run_wsgi_app</span><span class="params">(app)</span>:</span></span><br><span class="line">    <span class="comment"># 构造一个server如下，主要创建一个neutron协程</span></span><br><span class="line">    server = wsgi.Server(<span class="string">"Neutron"</span>)</span><br><span class="line">    <span class="comment"># 进行端口监听，响应API的请求</span></span><br><span class="line">    <span class="comment"># 因为可以创建多个api worker，目前没细看怎么调度</span></span><br><span class="line">    server.start(app, cfg.CONF.bind_port, cfg.CONF.bind_host,</span><br><span class="line">                 workers=_get_api_workers())</span><br><span class="line">    <span class="keyword">return</span> server</span><br><span class="line"></span><br><span class="line"><span class="comment"># neutron/wsgi.py</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Server</span><span class="params">(object)</span>:</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self, name, num_threads=None, disable_ssl=False)</span>:</span></span><br><span class="line">        eventlet.wsgi.MAX_HEADER_LINE = CONF.max_header_line</span><br><span class="line">        self.num_threads = num_threads <span class="keyword">or</span> CONF.wsgi_default_pool_size</span><br><span class="line">        self.disable_ssl = disable_ssl</span><br><span class="line">        <span class="comment"># 创建协程</span></span><br><span class="line">        self.pool = eventlet.GreenPool(<span class="number">1</span>)</span><br><span class="line">        self.name = name</span><br><span class="line">        self._server = <span class="keyword">None</span></span><br><span class="line">        self.client_socket_timeout = CONF.client_socket_timeout <span class="keyword">or</span> <span class="keyword">None</span></span><br><span class="line">        <span class="keyword">if</span> CONF.use_ssl <span class="keyword">and</span> <span class="keyword">not</span> self.disable_ssl:</span><br><span class="line">            sslutils.is_enabled(CONF)</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">start</span><span class="params">(self, application, port, host=<span class="string">'0.0.0.0'</span>, workers=<span class="number">0</span>)</span>:</span></span><br><span class="line">        self._host = host</span><br><span class="line">        self._port = port</span><br><span class="line">        backlog = CONF.backlog</span><br><span class="line"></span><br><span class="line">        <span class="comment"># 创建监听，host:port(配置文件bind_host和bind_port)</span></span><br><span class="line">        <span class="comment"># 以及一些特性的配置</span></span><br><span class="line">        self._socket = self._get_socket(self._host,</span><br><span class="line">                                        self._port,</span><br><span class="line">                                        backlog=backlog)</span><br><span class="line">        self._launch(application, workers)</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">_get_socket</span><span class="params">(self, host, port, backlog)</span>:</span></span><br><span class="line">        bind_addr = (host, port)</span><br><span class="line">        <span class="comment"># 获取网络信息</span></span><br><span class="line">        info = socket.getaddrinfo(bind_addr[<span class="number">0</span>],</span><br><span class="line">                                  bind_addr[<span class="number">1</span>],</span><br><span class="line">                                  socket.AF_UNSPEC,</span><br><span class="line">                                  socket.SOCK_STREAM)[<span class="number">0</span>]</span><br><span class="line">        family = info[<span class="number">0</span>]</span><br><span class="line">        bind_addr = info[<span class="number">-1</span>]</span><br><span class="line"></span><br><span class="line">        sock = <span class="keyword">None</span></span><br><span class="line">        <span class="comment"># 创建监听</span></span><br><span class="line">        sock = eventlet.listen(bind_addr,</span><br><span class="line">                               backlog=backlog,</span><br><span class="line">                               family=family)</span><br><span class="line">        <span class="comment"># 允许重用</span></span><br><span class="line">        sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, <span class="number">1</span>)</span><br><span class="line">        <span class="comment"># 支持keepalive</span></span><br><span class="line">        sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, <span class="number">1</span>)</span><br><span class="line"></span><br><span class="line">        <span class="comment"># 配置idle time</span></span><br><span class="line">        <span class="keyword">if</span> hasattr(socket, <span class="string">'TCP_KEEPIDLE'</span>):</span><br><span class="line">            sock.setsockopt(socket.IPPROTO_TCP,</span><br><span class="line">                            socket.TCP_KEEPIDLE,</span><br><span class="line">                            CONF.tcp_keepidle)</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> sock</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">_launch</span><span class="params">(self, application, workers=<span class="number">0</span>)</span>:</span></span><br><span class="line">        service = WorkerService(self, application, self.disable_ssl, workers)</span><br><span class="line">        api.context_manager.dispose_pool()</span><br><span class="line">        <span class="comment"># 创建管道</span></span><br><span class="line">        self._server = common_service.ProcessLauncher(cfg.CONF,</span><br><span class="line">                                                      wait_interval=<span class="number">1.0</span>)</span><br><span class="line">        <span class="comment"># 启动n个api workers进程</span></span><br><span class="line">        self._server.launch_service(service,</span><br><span class="line">                                    workers=service.worker_process_count)</span><br></pre></td></tr></table></figure><h1 id="Core-API-amp-Extension-API-1"><a href="#Core-API-amp-Extension-API-1" class="headerlink" title="Core API &amp; Extension API"></a>Core API &amp; Extension API</h1><hr><p>未完待续。。。其实是因为没时间看这块了。。。</p></div><div></div><footer class="post-footer"><div class="post-nav"><div class="post-nav-next post-nav-item"><a href="/2017/06/10/OPENSTACK/2017-06-10-neutron1/" rel="next" title="Neutron初识"><i class="fa fa-chevron-left"></i> Neutron初识</a></div><div class="post-nav-prev post-nav-item"> <a href="/2017/06/13/OPENSTACK/2017-06-13-neutron-dpdk/" rel="prev" title="Neutron集成DPDK">Neutron集成DPDK<i class="fa fa-chevron-right"></i></a></div></div></footer></div></article><div class="post-copyright"><p><span>注意:</span>所有文章非特别说明皆为原创。为保证信息与源同步，转载时请务必注明文章出处！谢谢合作 :-)</p><p> <span>原始链接:</span><a class="post-url" href="/2017/06/11/OPENSTACK/2017-06-11-neutron2/" title="Neutron Server 源码分析">http://zhaozhanxu.com/2017/06/11/OPENSTACK/2017-06-11-neutron2/</a><span class="copy-path" data-clipboard-text="原文: http://zhaozhanxu.com/2017/06/11/OPENSTACK/2017-06-11-neutron2/　　作者: 赵占旭" title="点击复制文章链接"><i class="fa fa-clipboard"></i></span><script src="/js/clipboard.min.js"></script><script>var clipboard=new Clipboard(".copy-path")</script></p><p> <span>许可协议:</span><i class="fa fa-creative-commons"></i> <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/cn" title="中国大陆 (CC BY-NC-SA 4.0 CN)" target="_blank">"署名-非商用-相同方式共享 4.0"</a> 转载请保留原文链接及作者。</p></div></div></div><div class="comments" id="comments"></div></div><div class="sidebar-toggle"><div class="sidebar-toggle-line-wrap"><span class="sidebar-toggle-line sidebar-toggle-line-first"></span><span class="sidebar-toggle-line sidebar-toggle-line-middle"></span><span class="sidebar-toggle-line sidebar-toggle-line-last"></span></div></div><aside id="sidebar" class="sidebar"><div class="sidebar-inner"><ul class="sidebar-nav motion-element"><li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap"> Table of Contents</li><li class="sidebar-nav-overview" data-target="site-overview"> Overview</li></ul><section class="site-overview sidebar-panel"><div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person"> <a href="/about"><img class="site-author-image" itemprop="image" src="/images/public/me.jpg" alt="赵占旭"><p class="site-author-name" itemprop="name">赵占旭</p><p class="site-description motion-element" itemprop="description"></p></a></div><nav class="site-state motion-element"><div class="site-state-item site-state-posts"> <a href="/archives"><span class="site-state-item-count">61</span> <span class="site-state-item-name">posts</span></a></div><div class="site-state-item site-state-categories"> <a href="/categories"><span class="site-state-item-count">7</span> <span class="site-state-item-name">categories</span></a></div><div class="site-state-item site-state-tags"> <a href="/tags"><span class="site-state-item-count">14</span> <span class="site-state-item-name">tags</span></a></div></nav><div class="feed-link motion-element"><a href="/atom.xml" rel="alternate"><i class="fa fa-rss"></i> RSS</a></div><div class="links-of-author motion-element"><span class="links-of-author-item"><a href="mailto:zhaozhanxu@163.com" target="_blank" title="Mail"><i class="fa fa-fw fa-envelope"></i> Mail</a></span><span class="links-of-author-item"><a href="https://github.com/zhaozhanxu" target="_blank" title="GitHub"><i class="fa fa-fw fa-github"></i> GitHub</a></span><span class="links-of-author-item"><a href="https://www.linkedin.com/in/zhaozhanxu" target="_blank" title="LinkedIn"><i class="fa fa-fw fa-linkedin"></i> LinkedIn</a></span><span class="links-of-author-item"><a href="https://twitter.com/zhaozhanxu" target="_blank" title="Twitter"><i class="fa fa-fw fa-twitter"></i> Twitter</a></span><span class="links-of-author-item"><a href="/about/" target="_blank" title="Wechat"><i class="fa fa-fw fa-wechat"></i> Wechat</a></span><span class="links-of-author-item"><a href="/about/" target="_blank" title="QQ"><i class="fa fa-fw fa-qq"></i> QQ</a></span></div><div class="links-of-blogroll motion-element links-of-blogroll-inline"><div class="links-of-blogroll-title"><i class="fa fa-fw fa-address-book"></i> 基情链接</div><ul class="links-of-blogroll-list"><li class="links-of-blogroll-item"> <a href="http://blog.csdn.net/jqh9804" title="呆子辉" target="_blank">呆子辉</a></li></ul></div></section><section class="post-toc-wrap motion-element sidebar-panel sidebar-panel-active"><div class="post-toc"><div class="post-toc-content"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#Neutron-Server-能力"><span class="nav-number">1.</span><span class="nav-text"><a href="#Neutron-Server-&#x80FD;&#x529B;" class="headerlink" title="Neutron Server &#x80FD;&#x529B;"></a> Neutron Server &#x80FD;&#x529B;</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#入口函数"><span class="nav-number">2.</span><span class="nav-text"><a href="#&#x5165;&#x53E3;&#x51FD;&#x6570;" class="headerlink" title="&#x5165;&#x53E3;&#x51FD;&#x6570;"></a> &#x5165;&#x53E3;&#x51FD;&#x6570;</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#Core-API-amp-Extension-API"><span class="nav-number">3.</span><span class="nav-text"><a href="#Core-API-amp-Extension-API" class="headerlink" title="Core API &amp; Extension API"></a> Core API &amp; Extension API</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#Core-API-amp-Extension-API-1"><span class="nav-number">4.</span><span class="nav-text"><a href="#Core-API-amp-Extension-API-1" class="headerlink" title="Core API &amp; Extension API"></a> Core API &amp; Extension API</span></a></li></ol></div></div></section></div></aside></div></main><footer id="footer" class="footer"><div class="footer-inner"><div class="copyright"> &copy; 2016 - <span itemprop="copyrightYear">2017</span><span class="with-love"><i class="fa fa-heart"></i></span> <span class="author" itemprop="copyrightHolder">赵占旭</span></div><div class="powered-by"> Powered by <a class="theme-link" href="https://hexo.io">Hexo</a></div><div class="theme-info"> Theme - <a class="theme-link" href="https://github.com/iissnan/hexo-theme-next">NexT</a></div><div class="busuanzi-count"><script async src="https://dn-lbstatics.qbox.me/busuanzi/2.3/busuanzi.pure.mini.js"></script><span class="site-uv"><i class="fa fa-user"></i><span class="busuanzi-value" id="busuanzi_value_site_uv"></span></span><span class="site-pv"><i class="fa fa-eye"></i><span class="busuanzi-value" id="busuanzi_value_page_pv"></span></span></div></div></footer><div class="back-to-top"><i class="fa fa-arrow-up"></i></div></div><script type="text/javascript">"[object Function]"!==Object.prototype.toString.call(window.Promise)&&(window.Promise=null)</script><script type="text/javascript" src="/lib/jquery/index.js?v=2.1.3"></script><script type="text/javascript" src="/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script><script type="text/javascript" src="/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script><script type="text/javascript" src="/lib/velocity/velocity.min.js?v=1.2.1"></script><script type="text/javascript" src="/lib/velocity/velocity.ui.min.js?v=1.2.1"></script><script type="text/javascript" src="/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script><script type="text/javascript" src="/lib/canvas-nest/canvas-nest.min.js"></script><script type="text/javascript" src="/js/src/utils.js?v=5.1.0"></script><script type="text/javascript" src="/js/src/motion.js?v=5.1.0"></script><script type="text/javascript" src="/js/src/affix.js?v=5.1.0"></script><script type="text/javascript" src="/js/src/schemes/pisces.js?v=5.1.0"></script><script type="text/javascript" src="/js/src/scrollspy.js?v=5.1.0"></script><script type="text/javascript" src="/js/src/post-details.js?v=5.1.0"></script><script type="text/javascript" src="/js/src/bootstrap.js?v=5.1.0"></script><script type="text/javascript">function proceedsearch(){$("body").append('<div class="popoverlay">').css("overflow","hidden"),$(".popup").toggle()}var isfetched=!1,search_path="search.xml";0==search_path.length&&(search_path="search.xml");var path="/"+search_path,searchFunc=function(e,t,a){"use strict";$.ajax({url:e,dataType:"xml",async:!0,success:function(e){isfetched=!0,$(".popup").detach().appendTo(".header-inner");var r=$("entry",e).map(function(){return{title:$("title",this).text(),content:$("content",this).text(),url:$("url",this).text()}}).get(),c=document.getElementById(t),n=document.getElementById(a);c.addEventListener("input",function(){var e=0,t='<ul class="search-result-list">',a=this.value.trim().toLowerCase().split(/[\s\-]+/);n.innerHTML="",this.value.trim().length>1&&r.forEach(function(r){var c=!1,n=r.title.trim().toLowerCase(),s=r.content.trim().replace(/<[^>]+>/g,"").toLowerCase(),o=decodeURIComponent(r.url),i=-1,l=-1,p=-1;if(""!=n&&a.forEach(function(e,t){i=n.indexOf(e),l=s.indexOf(e),(i>=0||l>=0)&&(c=!0,0==t&&(p=l))}),c){e+=1,t+="<li><a href='"+o+"' class='search-result-title'>"+n+"</a>";var h=r.content.trim().replace(/<[^>]+>/g,"");if(p>=0){var u=p-20,d=p+80;u<0&&(u=0),0==u&&(d=50),d>h.length&&(d=h.length);var f=h.substring(u,d);a.forEach(function(e){var t=new RegExp(e,"gi");f=f.replace(t,'<b class="search-keyword">'+e+"</b>")}),t+='<p class="search-result">'+f+"...</p>"}t+="</li>"}}),t+="</ul>",0==e&&(t='<div id="no-result"><i class="fa fa-frown-o fa-5x" /></div>'),""==a&&(t='<div id="no-result"><i class="fa fa-search fa-5x" /></div>'),n.innerHTML=t}),proceedsearch()}})};$(".popup-trigger").click(function(e){e.stopPropagation(),0==isfetched?searchFunc(path,"local-search-input","local-search-result"):proceedsearch()}),$(".popup-btn-close").click(function(e){$(".popup").hide(),$(".popoverlay").remove(),$("body").css("overflow","")}),$(".popup").click(function(e){e.stopPropagation()})</script><script>!function(){var t=document.createElement("script"),e=window.location.protocol.split(":")[0];t.src="https"===e?"https://zz.bdstatic.com/linksubmit/push.js":"http://push.zhanzhang.baidu.com/push.js";var s=document.getElementsByTagName("script")[0];s.parentNode.insertBefore(t,s)}()</script></body></html>